import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:jpush_flutter/jpush_flutter.dart';
import 'package:riki_push/config/riki_push_config.dart';

/// 作者：宋佳宾
/// 日期：2021/4/2
/// 备注：jpush 极光推送相关
///
///

/// 上传错误日志
typedef OnUploadError = void Function(String type, String details, String code, String imId, String jId);

/// 绑定别名成功回调
typedef BindAliasSuccess = void Function(String successAlias);

class RikiJpush {
  factory RikiJpush() => _getInstance();

  static RikiJpush get instance => _getInstance();
  static RikiJpush _instance;

  static RikiJpush _getInstance() {
    if (_instance == null) {
      _instance = RikiJpush._internal();
    }
    return _instance;
  }

  JPush _jPush;

  RikiJpush._internal() {
    if (_jPush == null) _jPush = JPush();
  }

  /// 每次绑定别名计数器
  int _setAliasCount = 0;

  /// 每次绑定别名的次数
  static final int bindAliascount = 5;

  /// 绑定失败后的重试间隔时间
  int bindFaileTimeInterval = 3;

  OnUploadError _onUploadError;

  OnUploadError get onUploadError => _onUploadError;

  BindAliasSuccess _bindAliasSuccss;

  BindAliasSuccess get bindAliasSuccess => _bindAliasSuccss;

  /// 是否正在绑定
  bool _isBinding = false;

  bool get isBinding => _isBinding;

  /// 配置 jpush 信息
  /// [appKey] appid
  /// [channel] 通道
  Future setJpush(String appKey, String channel, bool production, debug) {
    _jPush.setup(
      appKey: appKey,
      channel: channel,
      production: production,
      debug: debug,
    );
    return Future.value();
  }

  /// 绑定别名
  /// [jpushAlias] 别名信息
  /// [onUploadError] 日志回调
  void bindJpushAlias({@required String jpushAlias, @required OnUploadError onUploadError, @required BindAliasSuccess bindAlias}) {
    //如果正在绑定 return
    if (isBinding) return;
    _isBinding = true;
    this._onUploadError = onUploadError;
    this._bindAliasSuccss = bindAlias;
    _setAliasCount = 0;
    _setJpushAlias(jpushAlias);
  }

  ///绑定 极光推送别名
  ///[如果绑定失败  间隔3秒中绑定一次  尝试5次 知道成功  或者 失败 ]
  void _setJpushAlias(String jpushId) {
    _setAliasCount++;
    if (_setAliasCount > bindAliascount) {
      _isBinding = false;
      return;
    }
    _jPush.setAlias(jpushId).then((map) {
      if (map != null) {
        if (map.containsKey('alias')) {
          bindAliasSuccess(map['alias']);
          _setAliasCount = 0;
          print('jpush绑定成功' + map['alias']);
        }
      }
    }).catchError(
      (error) {
        if (error is PlatformException) {
          onUploadError("JPUSH", error.message?.toString(), error.code?.toString(), null, jpushId);
          Future.delayed(
            Duration(seconds: bindFaileTimeInterval += 1),
            () {
              _setJpushAlias(jpushId);
            },
          );
          print('jpush绑定失败');
        }
      },
    );
  }

  /// 设置 ios 通知权限
  void iosApplyPushAuthority(bool isShow, {int delayedSeconds = 0}) {
    if (Platform.isIOS) {
      if (delayedSeconds == 0)
        _jPush.applyPushAuthority(NotificationSettingsIOS(sound: isShow, alert: isShow, badge: isShow));
      else
        Future.delayed(
            Duration(seconds: delayedSeconds), () => _jPush.applyPushAuthority(NotificationSettingsIOS(sound: isShow, alert: isShow, badge: isShow)));
    }
  }

  /// 清除消息
  void clearNotification({@required int notificationId}) {
    if (Platform.isAndroid) _jPush.clearNotification(notificationId: notificationId);
  }

  /// 清除所有的通知栏
  void clearAllNotification() => this._jPush.clearAllNotifications();

  /// 设置桌面 logo 数量角标
  void setJpushBadget({int badge}) {
    assert(badge != null);
    _jPush.setBadge(badge);
  }

  /// 设计极光回调方法
  void setJpushListener({
    EventHandler onReceiveNotification,
    EventHandler onOpenNotification,
    EventHandler onReceiveMessage,
  }) {
    _jPush.addEventHandler(
      // 接收通知回调方法。 系统会自动弹框
      onReceiveNotification: onReceiveNotification,
      // 点击唤醒应用
      onOpenNotification: onOpenNotification,
      // 接收自定义消息回调方法。message消息不会弹框
      onReceiveMessage: onReceiveMessage,
    );
  }

  ///注销别名
  Future unInitJPush() async {
    bindFaileTimeInterval = 3;
    this._isBinding = false;
    return Future.value();
  }
}
